#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include "tp_debug.h"
#include "scps.h"
#include "scpstp.h"
#include "scpsudp.h"
#include "scps_ip.h"

int scps_np_trequest (tp_Socket * s, scps_ts * ts, 
  route * nproute, uint32_t length, struct mbuff *m, u_char th_off);

extern unsigned short udp_id;

int udp_BuildHdr (udp_Socket *s, struct mbuff *mbuffer)
{
  udp_Header *uh;


  in_Header *nh;

  short offset;

  if (!(mbuffer))
    {
      LOG ("\ndisaster in udp_BuildHdr()\n");
      fflush (stdout);
      return (-1);
    }

  offset = (short) (s->th_off);
  uh = (udp_Header *) (mbuffer->m_pktdat + offset);


  offset = (short) (s->nh_off);
  nh = (in_Header *) (mbuffer->m_pktdat + offset);

  mbuffer->m_offset = offset;

  uh->srcPort = s->myport;
  uh->dstPort = s->hisport;
  uh->len = ntohs (mbuffer->m_ext.len + UDP_HDR_LEN);  /* data length */
  uh->checksum = 0;
  mbuffer->m_len = UDP_HDR_LEN;

  mbuffer->m_ext.checksum =  /* should we do the whole checksum at once? */
    data_checksum (((struct mbcluster *) mbuffer->m_ext.ext_buf),
       mbuffer->m_ext.len, mbuffer->m_ext.offset);

  udp_FinalCksum (s, mbuffer, uh);

  if (s->np_rqts.nl_protocol == NL_PROTOCOL_IPV4) { /* PDF WHY NOT NP */
  /* np_build_hdr */
  nh->nl_head.ipv4.vht = htons (0x4500);
  nh->nl_head.ipv4.identification = htons (udp_id++);
  nh->nl_head.ipv4.frag = 0;
  nh->nl_head.ipv4.ttlProtocol = htons ((250 << 8) + IPPROTO_UDP);
  nh->nl_head.ipv4.checksum = 0;
  nh->nl_head.ipv4.source = local_addr;
  nh->nl_head.ipv4.destination = htonl (s->his_ipv4_addr);    /* get rid of htonl everywhere??? */
  nh->nl_head.ipv4.length = s->np_size + s->sp_size + UDP_HDR_LEN + mbuffer->m_ext.len;
  nh->nl_head.ipv4.length = htons (nh->nl_head.ipv4.length);
  nh->nl_head.ipv4.checksum = ~checksum ((uint16_t *) nh, sizeof (in_Header));
  }
  return (1);

}

uint32_t udp_Coalesce (udp_Socket * s, uint32_t * bytes_sent)
{
  uint32_t long_temp;
  int cc = 0;
  struct mbuff *mbuffer;
  struct mbcluster *mbcluster;

  /* 
   * Build the headers in the output buffer, but then keep 
   * the actual data in the clusters - avoid an outbound copy.
   *
   * assume there is a out_msg structure available...
   *
   */

  mbuffer = deq_mbuff (s->send_buff);

  /*
   * Tweak the template length field - everything but network header 
   */

  long_temp = mbuffer->m_len + mbuffer->m_ext.len + s->np_size;

  if (s->np_rqts.nl_protocol == NL_PROTOCOL_IPV4) {
    s->ip_templ.nl_head.ipv4.length = htons (long_temp);
  }

  /*
   * Call ip_trequest() to build the network protocol header
   * and push the packet onto an interface/queue
   */


  if ((s->rt_route->current_credit >= long_temp) &&
      (bytes_sent) && (s->rt_route->max_burst_bytes >= long_temp))
    {
  switch (s->np_rqts.nl_protocol) {
    case NL_PROTOCOL_IPV4:
      cc = ip_trequest ((tp_Socket *) s, mbuffer, bytes_sent);
      break;
    case NL_PROTOCOL_NP:
      /* Fix this it's a mess, get rid of the 8 and put the right thing in */
      cc = scps_np_trequest ((tp_Socket *) s, NULL, NULL, *bytes_sent,
       mbuffer, 8);
      break;
  }
    }

  else
    {
      cc = 0;
      SET_ERR (SCPS_ENOBUFS);
    }

  if (cc)
    {
      s->rt_route->current_credit -= (int) long_temp;
      *bytes_sent = long_temp;
      s->total_data += long_temp;
    }
  /*
   * This all looks kind of crusty 
   */
  /* dequeue all clusters */
  for (mbcluster = deq_mclus (s->app_sbuff); mbcluster;
       mbcluster = deq_mclus (s->app_sbuff))
    free_mclus (mbcluster);

  s->app_sbuff->read_head = s->app_sbuff->write_head = NULL;
  s->app_sbuff->write_off = s->app_sbuff->bytes_beyond = 0;
  free_mbuff (mbuffer);    /* free mbuff and all clusters */

  if (!(mbuffer = alloc_mbuff (MT_HEADER)))  /* get back our mbuff */
    {
      SET_ERR (SCPS_ENOBUFS);
      exit (-1);    /* not the thing to do */
    }
  if (!(enq_mbuff (mbuffer, s->send_buff)))
    LOG ("MBUFFER ENQUEUEING ERROR in udp_Coalesce()\n");

  return (cc);
}
